/*-------------------------------------------------------------------------
 *
 * kwlookup.c
 *	  PostgreSQL 的关键字查找
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *	  src/common/kwlookup.c
 *
 *-------------------------------------------------------------------------
 */
#include "c.h"

#include "common/kwlookup.h"


/*
 * ScanKeywordLookup - 检查给定的单词是否是关键字
 *
 * 要匹配的关键字列表作为 ScanKeywordList 传入。
 *
 * 返回关键字的编号 (0..N-1)，如果没有匹配则返回 -1。
 * 调用方通常使用关键字编号来索引信息数组，但这与此代码无关。
 *
 * 匹配是不区分大小写的。请注意，我们故意使用一个
 * 简化的大小写转换，只将 'A'-'Z' 转换为 'a'-'z'，
 * 即便我们处于一个 tolower() 可能生成更多或不同
 * 转换的区域设置中。这是为了符合 SQL99 规范，该规范规定
 * 应以这种方式匹配关键字，即便非关键字标识符
 * 接收不同的大小写规范映射。
 */
int ScanKeywordLookup(const char *fc_str,
				  const ScanKeywordList *fc_keywords)
{
	size_t		fc_len;
	int			fc_h;
	const char *fc_kw;

	/*
	 * 如果长度超过关键字的限制，则立即拒绝。
	 * 这可以节省对长字符串进行无用哈希和小写转换的工作。
	 */
	fc_len = strlen(fc_str);
	if (fc_len > fc_keywords->max_kw_len)
		return -1;

	/*
	 * 计算哈希函数。我们假设它是生成
	 * 不区分大小写的结果。由于这是一个完美的哈希，
	 * 我们只需匹配它所标识的特定关键字。
	 */
	fc_h = fc_keywords->hash(fc_str, fc_len);

	/* 超出范围的结果表示没有匹配 */
	if (fc_h < 0 || fc_h >= fc_keywords->num_keywords)
		return -1;

	/*
	 * 逐字符比较以查看是否匹配，对输入字符应用
	 * ASCII-only 小写转换。我们不能使用
	 * tolower()，因为在某些区域设置中，它可能会产生错误的转换
	 * （例如土耳其语）。
	 */
	fc_kw = GetScanKeyword(fc_h, fc_keywords);
	while (*fc_str != '\0')
	{
		char		fc_ch = *fc_str++;

		if (fc_ch >= 'A' && fc_ch <= 'Z')
			fc_ch += 'a' - 'A';
		if (fc_ch != *fc_kw++)
			return -1;
	}
	if (*fc_kw != '\0')
		return -1;

	/* 成功！ */
	return fc_h;
}
